using System;
using System.Collections;
using EnvDTE;
using System.ComponentModel;
using Microsoft.VisualStudio.VCCodeModel;

namespace DoxyComment
{
	/// <summary>
	/// 
	/// </summary>
	[CommentProviderFriendlyName("Default")]
	internal class DefaultCommentProvider :
		ICommentProvider
	{
		[CommentProviderProperty]
		private string firstLineTag = "/*!";
		[CommentProviderProperty]
		private string normalLineTag = " * ";
		[CommentProviderProperty]
		private string lastLineTag = " */";

		public DefaultCommentProvider()
		{
		}

		[Category("Comment block look"),
		Description("Prefix for first line of comment block.")]
		public string FirstLineTag
		{
			get
			{
				return firstLineTag;
			}
			set
			{
				firstLineTag = value;
			}
		}

		[Category("Comment block look"),
		Description("Prefix for normal line of comment block.")]
		public string NormalLineTag
		{
			get
			{
				return normalLineTag;
			}
			set
			{
				normalLineTag = value;
			}
		}

		[Category("Comment block look"),
		Description("Prefix for last line of comment block.")]
		public string LastLineTag
		{
			get
			{
				return lastLineTag;
			}
			set
			{
				lastLineTag = value;
			}
		}

		#region ICommentProvider implementation

		/// <summary>
		/// Function creates a comment block header.
		/// </summary>
		/// <param name="codeElem"></param>
		/// <returns></returns>
		private ArrayList CreateCommentHeader(VCCodeElement codeElem) 
		{ 
			ArrayList rv = new ArrayList();

			if (FirstLineTag.Length > 0)
			{
				rv.Add(FirstLineTag);
			}

			rv.Add(NormalLineTag + "\\brief");
			rv.Add(NormalLineTag + "Write brief comment for " + codeElem.Name + " here."); 
			rv.Add(NormalLineTag);
			return rv; 
		} 

		/// <summary>
		/// Function creates a comment block footer.
		/// </summary>
		/// <param name="codeElem"></param>
		/// <param name="buffer"></param>
		/// <returns></returns>
		private void AppendCommentFooter(VCCodeElement codeElem,ArrayList buffer) 
		{ 
			buffer.Add(NormalLineTag + "Write detailed description for " + codeElem.Name + " here.");
			buffer.Add(NormalLineTag);
			buffer.Add(NormalLineTag + "\\remarks");
			buffer.Add(NormalLineTag + "Write remarks for " + codeElem.Name + " here.");
			buffer.Add(NormalLineTag);
			buffer.Add(NormalLineTag + "\\see");
			buffer.Add(NormalLineTag + "Separate items with the '|' character.");

			// Does the comment provider require a last line tag?
			if (LastLineTag.Length > 0)
			{
				buffer.Add(LastLineTag);
			}
		} 

		public string[] CreateFileComment(Document doc,Project proj)
		{
			ArrayList rv = new ArrayList();

			// Begin tag?
			if (FirstLineTag.Length > 0)
			{
				rv.Add(FirstLineTag);
			}

			rv.Add(NormalLineTag + "<File comment goes here!!>");
			rv.Add(NormalLineTag);
			rv.Add(NormalLineTag + "Copyright (c) 2005 by <your name/ organization here>");
            rv.Add(proj.Name);
			
			// End tag?
			if (LastLineTag.Length > 0)
			{
				rv.Add(LastLineTag);
			}

			return (string[])rv.ToArray(typeof(string));
		}

		public string[] CreateTypeDefComment(VCCodeTypedef codeElem)
		{ 
			ArrayList rv;

			rv = CreateCommentHeader((VCCodeElement)codeElem); 
			AppendCommentFooter((VCCodeElement)codeElem,rv); 

			return (string[])rv.ToArray(typeof(string)); 
		} 

		public string[] CreateUnionComment(VCCodeUnion codeElem)
		{ 
			ArrayList rv;

			rv = CreateCommentHeader((VCCodeElement)codeElem); 
			AppendCommentFooter((VCCodeElement)codeElem,rv); 

			return (string[])rv.ToArray(typeof(string)); 
		} 

		public string[] CreateMacroComment(VCCodeMacro codeElem)
		{ 
			ArrayList rv; 

			rv = CreateCommentHeader((VCCodeElement)codeElem); 
			if ((codeElem.Parameters.Count > 0)) 
			{ 
				foreach (VCCodeParameter curParam in codeElem.Parameters) 
				{ 
					rv.Add(NormalLineTag + "\\param " + curParam.Name);
					rv.Add(NormalLineTag + "Description of parameter " + curParam.Name + ".");
					rv.Add(NormalLineTag);
				} 
			} 
			AppendCommentFooter((VCCodeElement)codeElem,rv); 

			return (string[])rv.ToArray(typeof(string)); 
		} 

		public string[] CreateStructComment(VCCodeStruct codeElem)
		{ 
			ArrayList rv;

			rv = CreateCommentHeader((VCCodeElement)codeElem); 
			AppendCommentFooter((VCCodeElement)codeElem,rv); 

			return (string[])rv.ToArray(typeof(string)); 
		} 

		public string[] CreateNamespaceComment(VCCodeNamespace codeElem)
		{ 
			ArrayList rv;

			rv = CreateCommentHeader((VCCodeElement)codeElem); 
			AppendCommentFooter((VCCodeElement)codeElem,rv); 

			return (string[])rv.ToArray(typeof(string)); 
		} 

		public string[] CreateFunctionComment(VCCodeFunction codeElem)
		{ 
			ArrayList rv; 

			rv = CreateCommentHeader((VCCodeElement)codeElem);

			// Create /param sections for each parameters in the function
			if (codeElem.Parameters.Count > 0) 
			{ 
				foreach (VCCodeParameter curParam in codeElem.Parameters) 
				{ 
					rv.Add(NormalLineTag + "\\param " + curParam.Name);
					rv.Add(NormalLineTag + "Description of parameter " + curParam.Name + ".");
					rv.Add(NormalLineTag);
				} 
			}

			// Create /returns section
			if ((codeElem.TypeString.Length > 0) &
				(codeElem.TypeString.ToLower() != "void")) 
			{ 
				rv.Add(NormalLineTag + "\\returns");
				rv.Add(NormalLineTag + "Write description of return value here.");
				rv.Add(NormalLineTag);
			} 

			// Create /throws section
			rv.Add(NormalLineTag + "\\throws <exception class>");
			rv.Add(NormalLineTag + "Description of criteria for throwing this exception."); 
			rv.Add(NormalLineTag);

			AppendCommentFooter((VCCodeElement)codeElem,rv); 

			return (string[])rv.ToArray(typeof(string)); 
		} 

		public string[] CreateEnumValueComment(VCCodeVariable codeElem)
		{ 
			ArrayList rv = new ArrayList();

			if (FirstLineTag.Length > 0)
			{
				rv.Add(FirstLineTag);
			}

			rv.Add(NormalLineTag + "\\brief");
			rv.Add(NormalLineTag + "Write brief comment for " + codeElem.Name + " here."); 

			// End tag required?
			if (LastLineTag.Length > 0)
			{
				rv.Add(LastLineTag);
			}

			return (string[])rv.ToArray(typeof(string)); 
		} 

		public string[] CreateEnumComment(VCCodeEnum codeElem)
		{ 
			ArrayList rv;

			rv = CreateCommentHeader((VCCodeElement)codeElem); 
			AppendCommentFooter((VCCodeElement)codeElem,rv); 

			return (string[])rv.ToArray(typeof(string)); 
		} 

		public string[] CreateVariableComment(VCCodeVariable codeElem)
		{ 
			ArrayList rv;

			rv = CreateCommentHeader((VCCodeElement)codeElem); 
			AppendCommentFooter((VCCodeElement)codeElem,rv); 

			return (string[])rv.ToArray(typeof(string)); 
		} 

		public string[] CreateClassComment(VCCodeClass codeElem)
		{ 
			ArrayList rv; 

			// Header
			rv = CreateCommentHeader((VCCodeElement)codeElem); 

			// Template parameters?
			if ((codeElem.IsTemplate)) 
			{ 
				foreach (VCCodeParameter curTemplateParam in codeElem.Templatizations) 
				{ 
					string typeStr; 
					if ((curTemplateParam.Name.Length != 0)) 
					{ 
						typeStr = curTemplateParam.Name; 
					} 
					else 
					{ 
						// For some strange reason normal class template
						// parameters do not have a names. Instead the name is
						// placed in the type property as 'typename XXX'. This
						// code simply copies the XXX part as the template
						// parameter name.
						int typeIdx; 

						typeIdx = curTemplateParam.TypeString.LastIndexOf(" "); 
						typeStr = curTemplateParam.TypeString.Substring(typeIdx + 1); 
					} 

					rv.Add(NormalLineTag + "\\param " + typeStr);
					rv.Add(NormalLineTag + "Description of parameter " + typeStr + ".");
					rv.Add(NormalLineTag);
				} 
			} 

			AppendCommentFooter((VCCodeElement)codeElem,rv); 

			return (string[])rv.ToArray(typeof(string)); 
		} 

		#endregion
	}
}
